package com.sqlcheck.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * MyBatis SQL内容处理器
 * 实现宽容解析与最大化拼接策略
 * 
 * 核心设计原则：
 * - 将所有可能的SQL分支和片段都包含进来
 * - 生成的SQL字符串在语法上可能错误（如多个WHERE关键字、多余的AND）
 * - 这无关紧要，因为目的是兼容性分析而非SQL执行
 * - 确保不遗漏任何可能的兼容性问题
 */
@Slf4j
@Component
public class MybatisSqlContentProcessor {
    
    // SQL长度限制，避免内存问题
    private static final int MAX_SQL_LENGTH = 100000; // 100KB限制
    
    /**
     * 统一处理MyBatis SQL内容，最大化拼接
     * @param rawSql 原始SQL内容
     * @param sourceType 来源类型 (ANNOTATION/XML)
     * @return 处理后的SQL内容
     */
    public String processComplexSql(String rawSql, String sourceType) {
        if (rawSql == null) {
            return rawSql;
        }
        
        // 处理空字符串和纯空白字符串
        if (rawSql.trim().isEmpty()) {
            return "";
        }
        
        // 长度限制检查
        if (rawSql.length() > MAX_SQL_LENGTH) {
            log.warn("SQL内容超过长度限制: {} > {}", rawSql.length(), MAX_SQL_LENGTH);
            return rawSql.substring(0, MAX_SQL_LENGTH) + "... [TRUNCATED]";
        }
        
        log.debug("开始处理复杂SQL: sourceType={}, length={}", sourceType, rawSql.length());
        
        String processed = rawSql;
        
        try {
            // 如果包含script标签，进行特殊处理
            if (processed.contains("<script>")) {
                processed = processScriptContent(processed);
            }
            
            // 处理CDATA区块
            processed = processCDataSections(processed);
            
            // 最大化拼接动态SQL
            processed = extractAllDynamicSqlContent(processed);
            
            // 基础格式化
            processed = basicFormat(processed);
            
            log.debug("SQL处理完成: 原长度={}, 处理后长度={}", rawSql.length(), processed.length());
            
            return processed;
            
        } catch (Exception e) {
            log.warn("复杂SQL处理失败，使用安全降级策略: {}", e.getMessage());
            // 安全降级策略：确保基本的SQL结构完整性
            return processWithFallbackStrategy(rawSql);
        }
    }
    
    /**
     * 处理script标签内容
     */
    private String processScriptContent(String sql) {
        return sql.replaceAll("(?s)<script[^>]*>(.*?)</script>", "$1");
    }
    
    /**
     * 处理CDATA区块
     */
    private String processCDataSections(String sql) {
        return sql.replaceAll("(?s)<!\\[CDATA\\[(.*?)\\]\\]>", "$1");
    }
    
    /**
     * 最大化提取动态SQL内容 - 宽容解析策略（安全版本）
     */
    private String extractAllDynamicSqlContent(String sql) {
        try {
            // 逐个处理动态标签，使用更安全的正则表达式
            sql = processIfTags(sql);
            sql = processChooseTags(sql);
            sql = processWhenTags(sql);
            sql = processOtherwiseTags(sql);
            sql = processWhereTags(sql);
            sql = processSetTags(sql);
            sql = processTrimTags(sql);
            sql = processForeachTags(sql);
            sql = processBindTags(sql);
            
            return sql;
        } catch (Exception e) {
            log.warn("动态SQL标签处理失败，使用简单清理: {}", e.getMessage());
            // 降级：简单移除标签但保留内容
            return removeTagsSimple(sql);
        }
    }
    
    private String processIfTags(String sql) {
        return sql.replaceAll("(?s)<if[^>]*>(.*?)</if>", " $1 ");
    }
    
    private String processChooseTags(String sql) {
        return sql.replaceAll("(?s)<choose[^>]*>(.*?)</choose>", " $1 ");
    }
    
    private String processWhenTags(String sql) {
        return sql.replaceAll("(?s)<when[^>]*>(.*?)</when>", " $1 ");
    }
    
    private String processOtherwiseTags(String sql) {
        return sql.replaceAll("(?s)<otherwise[^>]*>(.*?)</otherwise>", " $1 ");
    }
    
    private String processWhereTags(String sql) {
        return sql.replaceAll("(?s)<where[^>]*>(.*?)</where>", " WHERE $1 ");
    }
    
    private String processSetTags(String sql) {
        return sql.replaceAll("(?s)<set[^>]*>(.*?)</set>", " SET $1 ");
    }
    
    private String processTrimTags(String sql) {
        return sql.replaceAll("(?s)<trim[^>]*>(.*?)</trim>", " $1 ");
    }
    
    private String processForeachTags(String sql) {
        return sql.replaceAll("(?s)<foreach[^>]*>(.*?)</foreach>", " $1 ");
    }
    
    private String processBindTags(String sql) {
        // 安全处理bind标签 - 分别处理自闭合和配对标签
        sql = sql.replaceAll("(?s)<bind[^>]*/>", "");
        sql = sql.replaceAll("(?s)<bind[^>]*>.*?</bind>", "");
        return sql;
    }
    
    private String removeTagsSimple(String sql) {
        // 简单降级策略：移除所有角括号标签但保留内容
        sql = sql.replaceAll("<[^>]+>", " ");
        return sql.replaceAll("\\s+", " ").trim();
    }
    
    /**
     * 安全降级策略 - 当正则表达式处理失败时的备选方案
     */
    private String processWithFallbackStrategy(String sql) {
        try {
            // 简单但安全的处理策略
            // 1. 处理script标签
            if (sql.contains("<script>")) {
                sql = sql.replaceAll("(?s)<script[^>]*>", "")
                         .replaceAll("(?s)</script>", "");
            }
            
            // 2. 处理CDATA
            if (sql.contains("CDATA")) {
                sql = sql.replaceAll("(?s)<!\\[CDATA\\[", "")
                         .replaceAll("(?s)\\]\\]>", "");
            }
            
            // 3. 简单移除所有XML标签但保留内容
            sql = sql.replaceAll("<[^>]+>", " ");
            
            // 4. 基础清理
            return basicFormat(sql);
            
        } catch (Exception e2) {
            log.error("降级策略也失败了，返回原始内容: {}", e2.getMessage());
            // 最后的兜底：只做最基础的空白符处理
            return sql.replaceAll("\\s+", " ").trim();
        }
    }
    
    /**
     * 基础格式化 - 仅做最必要的清理
     * 
     * 遵循宽容原则：
     * - 只做最基础的格式化
     * - 不尝试修复语法错误
     * - 保持原有的业务逻辑结构
     */
    private String basicFormat(String sql) {
        if (sql == null) return null;
        
        // 只做最基础的格式化
        sql = sql.replaceAll("\\s+", " ").trim();
        
        // 移除一些明显的多余符号，但保持宽容
        sql = sql.replaceAll("^\\s*WHERE\\s+AND\\s+", "WHERE ");
        sql = sql.replaceAll("\\s+WHERE\\s+AND\\s+", " WHERE ");
        
        // 清理可能的多余空格
        sql = sql.replaceAll("\\s*#\\{", " #{");
        sql = sql.replaceAll("\\}\\s*", "} ");
        sql = sql.replaceAll("\\s*\\$\\{", " ${");
        
        return sql;
    }
    
    /**
     * 验证SQL内容是否需要特殊处理
     */
    public boolean needsComplexProcessing(String sql) {
        if (sql == null) return false;
        
        return sql.contains("<script>") || 
               sql.contains("<if") || 
               sql.contains("<choose") || 
               sql.contains("<where") ||
               sql.contains("<set") ||
               sql.contains("<trim") ||
               sql.contains("<foreach") ||
               sql.contains("CDATA");
    }
    
    /**
     * 获取SQL内容处理统计信息（用于监控和调试）
     */
    public String getProcessingStats(String originalSql, String processedSql) {
        if (originalSql == null || processedSql == null) {
            return "无法计算统计信息";
        }
        
        return String.format("原长度: %d, 处理后长度: %d, 压缩率: %.2f%%",
                originalSql.length(),
                processedSql.length(),
                (1.0 - (double) processedSql.length() / originalSql.length()) * 100);
    }
}